﻿using System.Diagnostics.CodeAnalysis;
using System.Reflection;

namespace Devonline.Core;

/// <summary>
/// 成员比较器, 用户判断一个类型中的全部成员的值是否相等
/// </summary>
/// <typeparam name="T"></typeparam>
public class MemberEqualityComparer<T> : IEqualityComparer<T>
{
    public bool Equals(T? x, T? y)
    {
        var propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (var propertyInfo in propertyInfos)
        {
            var valueX = propertyInfo.GetValue(x);
            var valueY = propertyInfo.GetValue(y);
            if (!(propertyInfo.PropertyType.IsValueType || valueX == valueY) || (propertyInfo.PropertyType.IsValueType && valueX?.ToString() != valueY?.ToString()))
            {
                return false;
            }
        }

        return true;
    }

    public int GetHashCode([DisallowNull] T obj) => obj.GetHashCode();
}

/// <summary>
/// 字段相等比较器, 用于判断一个类型中某一个字段的值是否相等
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="keySelecter"></param>
public class MemberEqualityComparer<T, TKey>(Func<T, TKey> keySelecter) : IEqualityComparer<T>
{
    private readonly Func<T, TKey> _keySelecter = keySelecter;

    public bool Equals(T? x, T? y)
    {
        if (x is null || y is null)
        {
            return false;
        }

        return _keySelecter(x)?.Equals(_keySelecter(y)) ?? false;
    }

    public int GetHashCode([DisallowNull] T obj) => obj.GetHashCode();
}